--------------------------------------------------------------------------------
-- Module Declaration
--

local mod, CL = BigWigs:NewBoss("The Lich King", 604)
if not mod then return end
mod:RegisterEnableMob(36597, 38995) -- The Lich King, Highlord Tirion Fordring
mod.toggleOptions = {72143, 70541, {70337, "ICON", "FLASH"}, 70372, {72762, "SAY", "ICON", "FLASH"}, 69409, 69037, {68980, "ICON", "FLASH"}, 70498, {68981, "FLASH"}, 69200, {72262, "FLASH"}, 72350, {73529, "SAY", "FLASH", "ICON"}, "warmup", "berserk", "bosskill"}
mod.optionHeaders = {
	[72143] = CL.phase:format(1),
	[72762] = CL.phase:format(2),
	[68980] = CL.phase:format(3),
	[68981] = "Transition",
	[73529] = "heroic",
	warmup = "general",
}

--------------------------------------------------------------------------------
-- Locals
--

local phase = 0
local frenzied = {}
local plagueTicks = {}

--------------------------------------------------------------------------------
-- Localization
--

local L = mod:NewLocale("enUS", true)
if L then
	L.warmup_trigger = "So the Light's vaunted justice has finally arrived"
	L.engage_trigger = "I'll keep you alive to witness the end, Fordring."

	L.horror_message = "Shambling Horror"
	L.horror_bar = "Next Horror"

	L.valkyr_message = "Val'kyr"
	L.valkyr_bar = "Next Val'kyr"
	L.valkyrhug_message = "Val'kyrs Hugged"

	L.cave_phase = "Cave Phase"
	L.last_phase_bar = "Last Phase"

	L.frenzy_bar = "%s frenzies!"
	L.frenzy_survive_message = "%s will survive after plague"
	L.frenzy_message = "Add frenzied!"
	L.frenzy_soon_message = "5sec to frenzy!"
end
L = mod:GetLocale()

--------------------------------------------------------------------------------
-- Initialization
--


function mod:OnBossEnable()
	-- Phase 1
	self:Log("SPELL_CAST_START", "Infest", 70541)
	self:Log("SPELL_CAST_SUCCESS", "NecroticPlague", 70337, 70338)
	self:Log("SPELL_DISPEL", "PlagueScan", "*")
	self:Log("SPELL_SUMMON", "Horror", 70372)
	self:Log("SPELL_CAST_START", "Enrage", 72143)
	self:Log("SPELL_AURA_APPLIED", "Frenzy", 28747)
	self:Log("SPELL_PERIODIC_DAMAGE", "PlagueTick", 70337, 70338)

	-- Phase 2
	self:Log("SPELL_CAST_SUCCESS", "SoulReaper", 69409)
	self:Log("SPELL_CAST_START", "DefileCast", 72762)
	self:Log("SPELL_DAMAGE", "DefileRun", 72754)
	self:Log("SPELL_MISSED", "DefileRun", 72754)
	self:Log("SPELL_SUMMON", "Valkyr", 69037)

	-- Phase 3
	self:Log("SPELL_CAST_SUCCESS", "HarvestSoul", 68980)
	self:Log("SPELL_AURA_REMOVED", "HSRemove", 68980)
	self:Log("SPELL_CAST_START", "VileSpirits", 70498)

	-- Transition phases
	self:Log("SPELL_CAST_START", "RemorselessWinter", 68981, 72259)
	self:Log("SPELL_CAST_SUCCESS", "RagingSpirit", 69200)
	self:Log("SPELL_CAST_START", "Quake", 72262)

	self:Log("SPELL_CAST_START", "FuryofFrostmourne", 72350)

	-- Hard Mode
	self:Log("SPELL_CAST_START", "ShadowTrap", 73539)

	self:Death("Win", 36597)

	self:RegisterEvent("PLAYER_REGEN_ENABLED", "CheckForWipe")
	self:Yell("Warmup", L["warmup_trigger"])
	self:Yell("Engage", L["engage_trigger"])
end

function mod:Warmup()
	self:Bar("warmup", 53, self.displayName, "achievement_boss_lichking")
end

function mod:OnEngage()
	wipe(frenzied)
	wipe(plagueTicks)

	self:Berserk(900)
	self:Bar(70337, 31) -- Necrotic Plague
	self:CDBar(70372, 22, L["horror_bar"])
	phase = 1
	if self:Heroic() then
		self:Bar(73529, 16)
	end
end

--------------------------------------------------------------------------------
-- Event Handlers
--

function mod:PlagueTick(args)
	if not self:Heroic() then return end -- Doesn't apply on normal diff.
	-- Not ticking on a Shambling Horror, so bail early
	if self:MobId(args.destGUID) ~= 37698 then return end

	plagueTicks[args.destGUID] = (plagueTicks[args.destGUID] or 0) + 1
	if plagueTicks[args.destGUID] == 3 then
		plagueTicks[args.destGUID] = nil
		return
	end

	-- Search by full GUID, so we don't mistake one shambler for another
	local unitId = self:GetUnitIdByGUID(args.destGUID)
	if not unitId then return end

	-- Shambler is already frenzied, will it die from the plague or endure
	-- for a longer period?
	if frenzied[args.destGUID] then
		local damageLeft = (3 - plagueTicks[args.destGUID]) * args.extraSpellId
		local hp = UnitHealth(unitId)
		if hp > damageLeft then
			self:Message(70372, L["frenzy_survive_message"]:format(args.destName), "Attention", 72143)
		end
	else
		local hp, max = UnitHealth(unitId), UnitHealthMax(unitId)
		if not max or max == 0 then return end
		local nextTickHP = hp - args.extraSpellId
		-- Will the shambler die from the next tick?
		if nextTickHP <= 0 then return end
		local percentHp = (nextTickHP / max) * 100
		-- This sucker will frenzy in 5 seconds
		if percentHp < 21 then
			self:Message(70372, "Important", "Info", L["frenzy_soon_message"], 72143)
			self:Bar(70372, 5, L["frenzy_bar"]:format(args.destName), 72143)
		end
	end
end

function mod:Frenzy(args)
	frenzied[args.destGUID] = true
	self:Message(70372, "Important", "Long", L["frenzy_message"], 72143)
end

function mod:Horror(args)
	self:Message(70372, "Attention", nil, L["horror_message"])
	self:CDBar(70372, 60, L["horror_bar"])
end

function mod:FuryofFrostmourne()
	self:StopBar(72762) -- Defile
	self:StopBar(69409) -- Soul Reaper
	self:StopBar(70498) -- Vile Spirits
	self:StopBar(68980) -- Harvest Soul
	self:Bar(72350, 160, L["last_phase_bar"])
end

function mod:Infest(args)
	self:Message(70541, "Urgent")
	self:CDBar(70541, 22)
end

function mod:VileSpirits(args)
	self:Message(70498, "Urgent")
	self:CDBar(70498, 30.5)
end

function mod:SoulReaper(args)
	self:TargetMessage(69409, args.destName, "Personal", "Alert")
	self:CDBar(69409, 30)
end

function mod:NecroticPlague(args)
	if self:Me(args.destGUID) then
		self:Flash(70337)
	end
	self:TargetMessage(70337, args.destName, "Personal", "Alert")
	self:Bar(70337, 30)
	self:SecondaryIcon(70337, args.destName)
end

do
	local plague = GetSpellInfo(70337)
	local function scanRaid()
		for i = 1, GetNumGroupMembers() do
			local player = GetRaidRosterInfo(i)
			local debuffed, _, _, _, _, _, expire = UnitDebuff(player, plague)
			if debuffed and (expire - GetTime()) > 13 then
				if UnitIsUnit(player, "player") then
					mod:Flash(70337)
				end
				mod:TargetMessage(70337, player, "Personal", "Alert")
				mod:SecondaryIcon(70337, player)
			end
		end
	end
	function mod:PlagueScan()
		self:ScheduleTimer(scanRaid, 0.8)
	end
end

function mod:Enrage(args)
	if self:Dispeller("enrage", true) then
		self:Message(72143, "Attention", "Alert")
		self:CDBar(72143, 21)
	else
		self:Message(72143, "Attention")
	end
end

function mod:RagingSpirit(args)
	self:TargetMessage(69200, args.destName, "Personal", "Alert")
	self:Bar(69200, 23) -- Raging Spirit
end

do
	local prev = 0
	function mod:DefileRun(args)
		local t = GetTime()
		if t-prev > 2 then
			prev = t
			if self:Me(args.destGUID) then
				self:Message(72762, "Personal", "Info", CL["you"]:format(args.spellName))
				self:Flash(72762)
			end
		end
	end
end

do
	local hugged, prev = mod:NewTargetList(), 0
	local function ValkyrHugCheck()
		for i=1, GetNumGroupMembers() do
			local player = GetRaidRosterInfo(i)
			if UnitInVehicle(player) then
				hugged[#hugged + 1] = player
			end
		end
		mod:TargetMessage(69037, hugged, "Urgent", nil, L["valkyrhug_message"], 71844)
	end
	function mod:Valkyr(args)
		local t = GetTime()
		if t-prev > 4 then
			prev = t
			self:Message(69037, "Attention", nil, L["valkyr_message"], 71844)
			self:Bar(69037, 46, L["valkyr_bar"], 71844)
			self:ScheduleTimer(ValkyrHugCheck, 6.1)
		end
	end
end

function mod:HarvestSoul(args)
	if self:Heroic() then
		self:StopBar(72762) -- Defile
		self:StopBar(69409) -- Soul Reaper
		self:StopBar(69200) -- Raging Spirit
		self:Bar(68980, 50, L["cave_phase"])
		self:Bar(68980, 105)
	else
		if self:Me(args.destGUID) then
			self:Flash(68980)
		end
		self:TargetMessage(68980, args.destName, "Attention")
		self:Bar(68980, 75)
		self:SecondaryIcon(68980, args.destName)
	end
end

function mod:HSRemove(args)
	self:SecondaryIcon(68980)
end

function mod:RemorselessWinter(args)
	phase = phase + 1
	self:StopBar(L["valkyr_bar"])
	self:StopBar(L["horror_bar"])
	self:StopBar(70337) -- Necrotic Plague
	self:StopBar(70541) -- Infest
	self:StopBar(72762) -- Defile
	self:StopBar(69409) -- Soul Reaper
	self:StopBar(73529) -- Shadow Trap

	self:Message(68981, "Urgent", "Long", CL["cast"]:format(args.spellName))
	self:Bar(72262, 62) -- Quake
	self:Bar(69200, 15) -- Raging Spirit
end

function mod:Quake(args)
	phase = phase + 1
	self:StopBar(69200) -- Raging Spirit
	self:Message(72262, "Urgent", "Long", CL["cast"]:format(args.spellName))
	self:Bar(72762, 37) -- Defile
	self:CDBar(70541, 13) -- Infest
	self:CDBar(69409, 39) -- Soul Reaper
	if phase == 3 then
		self:Bar(69037, 24, L["valkyr_bar"], 71844)
	elseif phase == 5 then
		self:CDBar(70498, 21) -- Vile Spirits
		self:Bar(68980, 12) -- Harvest Soul
	end
end

do
	local handle = nil
	local function scanTarget()
		local bossId = mod:GetUnitIdByGUID(36597)
		if not bossId then return end
		local bossTarget = bossId.."target"
		if UnitExists(bossTarget) then
			if UnitIsUnit(bossTarget, "player") then
				mod:Flash(72762)
				mod:Say(72762)
			end
			local target = mod:UnitName(bossTarget)
			mod:TargetMessage(72762, target, "Important", "Alert")
			mod:PrimaryIcon(72762, target)
		end
		handle = nil
	end
	function mod:DefileCast(args)
		self:CancelTimer(handle)
		self:Bar(72762, 32)
		handle = self:ScheduleTimer(scanTarget, 0.01, args.spellName)
	end
end

do
	local scheduled = nil
	local function trapTarget()
		scheduled = nil
		local bossId = mod:GetUnitIdByGUID(36597)
		if not bossId then return end
		local bossTarget = bossId.."target"
		if UnitExists(bossTarget) then
			if UnitIsUnit(bossTarget, "player") then
				mod:Flash(73529)
				mod:Say(73529)
			end
			local target = mod:UnitName(bossTarget)
			mod:TargetMessage(73529, target, "Attention")
			mod:PrimaryIcon(73529, target)
		end
	end
	function mod:ShadowTrap(args)
		if not scheduled then
			scheduled = self:ScheduleTimer(trapTarget, 0.01)
			self:Bar(73529, 16)
		end
	end
end

